/*
 * RenamerTool.java
 *
 * Created on December 30, 2009, 12:02 PM
 */

package torchtools.gui;

import java.awt.event.ActionEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.prefs.Preferences;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileSystemView;
import torchtools.binary.TLPlayerSave;
import torchtools.binary.TLSave;
import torchtools.io.IOUtil;

/**
 *
 * @author  Matt
 */
public class MiniEditor extends BaseTool {
    
    public static final String HELP_URL = "http://code.google.com/p/torchtools/wiki/MiniEditorHelp";
    
    private static final String HEADER = "<html><font style=\"font-size:13pt; " +
            "font-weight: bold;\">{0}</font> Level {1}{2}</html>";
    private static final String HEADER_EMPTY = "<html><font style=\"font-size:13pt; " +
            "font-weight: bold;\">No Save Specified</font></html>";
    private static final String HC_TEXT = " <font style=\"color: red; font-" +
            "weight: bold;\">HC</font>";
    private static final String GOLD_MSG = "{0} gp";
    
    protected boolean validSave = true;
    protected boolean readPet = true;
    
    public MiniEditor() {
        this(true);
    }
    
    /** Creates new form RenamerTool */
    public MiniEditor(boolean readPet) {
        this.readPet = readPet;
        initComponents();
        pack();
        setLocationRelativeTo(null);
        if (!readPet) {
            petField.setEnabled(false);
            petField.setText("Pet I/O Disabled");
        }
        
        nameField.getDocument().addDocumentListener(new DocumentListener() {
            public void insertUpdate(DocumentEvent e) {
                nameFieldChanged();
            }

            public void removeUpdate(DocumentEvent e) {
                nameFieldChanged();
            }

            public void changedUpdate(DocumentEvent e) {
                nameFieldChanged();
            }
        });
        
        clear();
        helpMenuItem.setText("Online Help");
    }
    
    protected void clear() {
        super.clear();
        headerLabel.setText(HEADER_EMPTY);
        nameField.setText("");
        if (readPet) {
            petField.setText("");
            petField.setEnabled(true);
        }
        goldLabel.setText(MessageFormat.format(GOLD_MSG, 0));
        goldSpinner.setModel(new SpinnerNumberModel(0, 0, 0, 1));
        goldSpinner.setValue(0);
    }
    
    protected void sendTo(File f) throws IOException {
        if (f!=null) {
            //first make sure it's a proper SVT file...
            TLPlayerSave receiver = new TLPlayerSave(f, "rw");
            
            //now we save the sender file with the new gold amount
            saveFile();
            
            //add the new gold to the receiver's pile
            int newGold = receiver.getGold() 
                    + ((Number)goldSpinner.getValue()).intValue();
            
            //write the new gold amount to the receiver and close the file
            receiver.writeGold(newGold);
            receiver.close();
        }
    }
    
    protected TLPlayerSave createPlayerSave(File path) throws IOException {
        TLPlayerSave save = new TLPlayerSave(path, "rw");
        if (readPet)
            save.readPetInfo();
        return save;
    }
    
    protected void helpAction(ActionEvent e) {
        openURL(HELP_URL);
    }
    
    protected void aboutAction(ActionEvent e) {
        String msg = "<html>Mini SVT Editor -- created by mattdesl.</html>";
        JOptionPane.showMessageDialog(this, msg, "About", JOptionPane.PLAIN_MESSAGE);
    }
    
    protected boolean saveFile() throws IOException {
        if (!validSave) {
            JOptionPane.showMessageDialog(this, "Enter valid names before saving!", 
                    "Error", JOptionPane.ERROR_MESSAGE);
            return true;
        }
        return super.saveFile();
    }
    
    protected boolean saveFileImpl() throws IOException {
        String oldName = save.getPlayerName();
        String oldPetName = save.getPetName();
        int oldGold = save.getGold();
        int oldDifficulty = save.getDifficulty();
        
        String name = nameField.getText();
        String petName = petField.getText();
        int difficulty = difficultyBox.getSelectedIndex();
        if (difficulty<0)
            difficulty = oldDifficulty;
        int sendAmt = ((Number)goldSpinner.getValue()).intValue();
        int gold = oldGold - sendAmt;
        
        if (gold != oldGold) {
            save.writeGold(gold);
            goldLabel.setText(MessageFormat.format(GOLD_MSG, gold));
        }
        if (difficulty != oldDifficulty) {
            save.writeDifficulty(difficulty);
        }
        boolean nameChange = !oldName.equals(name);
        boolean petNameChange = petField.isEnabled() && !oldPetName.equals(petName);
        boolean reload = nameChange && petNameChange;
        boolean success = true;
        if (nameChange) {
            System.out.println("changing name");
            save.seek(save.getPlayerNamePtr());
            int r = TLSave.replaceTLString(save, name);
            success = r!=-1;
            //if we need to re-open the stream
            if (reload && r!=0) {
                save.close();
                reloadFile(save.getFile());
            }
        }
        if (petNameChange) {
            System.out.println("changing pet name");
            save.seek(save.getPetNamePtr());
            int r = TLSave.replaceTLString(save, petName);
            if (success)
                success = r!=-1;
        }
        return success;
    }
    
    //opens the save file
    protected void openFile(File path) throws IOException {
        reloadFile(path);
        
        String hc = save.isHardcore() ? HC_TEXT : "";
        String s = MessageFormat.format(HEADER, save.getPlayerClass(), save.getLevel(), hc);
        headerLabel.setText(s);
        nameField.setText(save.getPlayerName());
        
        if (readPet) {
            boolean valid = save.getPetTypeID()!=TLPlayerSave.PET_UNKNOWN;
            petField.setEnabled(valid);
            petField.setText(valid ? save.getPetName() : "Unknown Pet");
        }
        
        difficultyBox.setSelectedIndex(save.getDifficulty());
        
        NumberFormat nf = NumberFormat.getIntegerInstance();
        nf.setGroupingUsed(true);
        int gold = save.getGold();
        goldLabel.setText(MessageFormat.format(GOLD_MSG, nf.format(gold)));
        
        int max = gold<0 ? 0 : gold;
        goldSpinner.setEnabled(gold>=0);
        goldSendTo.setEnabled(gold>=0);
        goldSpinner.setModel(new SpinnerNumberModel(0, 0, max, 1));
        goldSpinner.setValue(0);
        
        validSave = true;
    }
    
    public boolean isValidName(String name) {
        if (name.trim().length()==0)
            return false;
        return true;
    }
    
    public void nameFieldChanged() {
        validSave = isValidName(nameField.getText()) && isValidName(petField.getText());
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        nameField = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        goldSpinner = new javax.swing.JSpinner();
        goldSendTo = new javax.swing.JButton();
        goldLabel = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        headerLabel = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        difficultyBox = new javax.swing.JComboBox();
        jLabel2 = new javax.swing.JLabel();
        petField = new javax.swing.JTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Mini SVT Editor");

        nameField.setText("Tommy");

        jLabel1.setFont(jLabel1.getFont().deriveFont(jLabel1.getFont().getSize()-1f));
        jLabel1.setText("Player Name:");

        jLabel3.setFont(jLabel3.getFont().deriveFont(jLabel3.getFont().getSize()-1f));
        jLabel3.setText("Gold:");

        goldSpinner.setModel(new javax.swing.SpinnerNumberModel(0, 0, 0, 1));

        goldSendTo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/send.png"))); // NOI18N
        goldSendTo.setContentAreaFilled(false);
        goldSendTo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                goldSendToActionPerformed(evt);
            }
        });

        goldLabel.setFont(goldLabel.getFont().deriveFont(goldLabel.getFont().getStyle() | java.awt.Font.BOLD));
        goldLabel.setText("83,025 gp");
        goldLabel.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createLineBorder(java.awt.SystemColor.scrollbar), javax.swing.BorderFactory.createEmptyBorder(2, 4, 2, 4)));

        jLabel5.setFont(jLabel5.getFont().deriveFont(jLabel5.getFont().getSize()-1f));
        jLabel5.setText("Gold Transfer:");

        headerLabel.setFont(headerLabel.getFont().deriveFont(headerLabel.getFont().getSize()-1f));
        headerLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        headerLabel.setText("<html><font style=\"font-size:13pt; font-weight: bold;\">Alchemist</font>&nbsp; Level 3</html>");

        jLabel4.setFont(jLabel4.getFont().deriveFont(jLabel4.getFont().getSize()-1f));
        jLabel4.setText("Difficulty:");

        difficultyBox.setModel(new javax.swing.DefaultComboBoxModel(TLPlayerSave.DIFFICULTIES));

        jLabel2.setFont(jLabel2.getFont().deriveFont(jLabel2.getFont().getSize()-1f));
        jLabel2.setText("Pet Name:");

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(headerLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 213, Short.MAX_VALUE)
                    .add(nameField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 213, Short.MAX_VALUE)
                    .add(jLabel1)
                    .add(petField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 213, Short.MAX_VALUE)
                    .add(jLabel2)
                    .add(difficultyBox, 0, 213, Short.MAX_VALUE)
                    .add(jLabel4)
                    .add(goldLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 213, Short.MAX_VALUE)
                    .add(jLabel3)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                        .add(goldSpinner, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(goldSendTo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 18, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(jLabel5))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(headerLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 16, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jLabel1)
                .add(1, 1, 1)
                .add(nameField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(jLabel2)
                .add(1, 1, 1)
                .add(petField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(jLabel4)
                .add(1, 1, 1)
                .add(difficultyBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(jLabel3)
                .add(1, 1, 1)
                .add(goldLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(jLabel5)
                .add(1, 1, 1)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(goldSendTo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 17, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(goldSpinner, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 19, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    
    private void goldSendToActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goldSendToActionPerformed
        if (save==null)
            return;
        try {
            if (!validSave)
                throw new IllegalStateException();
            File f = showSaveChooser();
            if (f!=null && save!=null) {
                if (f.equals(save.getFile())) {
                    JOptionPane.showMessageDialog(this, "Can't send gold to yourself!", 
                            "Error", JOptionPane.ERROR_MESSAGE);
                } else {
                    sendTo(f);
                }
            }
        } catch (IllegalStateException e) {
            JOptionPane.showMessageDialog(this, "Enter valid names before " +
                    "saving!", "Error", JOptionPane.ERROR_MESSAGE);
        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Error transferring gold: " +
                    e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_goldSendToActionPerformed
    
    private static boolean in_array(String[] args, String s) {
        for (String a : args)
            if (s.equals(a))
                return true;
        return false;
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(final String[] args) {
        try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
        catch (Exception e) {}
        
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                boolean nopet = in_array(args, "-nopet"); 
                new MiniEditor(!nopet).setVisible(true);
            }
        });
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox difficultyBox;
    private javax.swing.JLabel goldLabel;
    private javax.swing.JButton goldSendTo;
    private javax.swing.JSpinner goldSpinner;
    private javax.swing.JLabel headerLabel;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JTextField nameField;
    private javax.swing.JTextField petField;
    // End of variables declaration//GEN-END:variables
    
}
